MySQL スレッド(編集中)
概要
MySQLは1プロセスで動作して複数の並行実行をスレッドで行う、シングルプロセスマルチスレッドモデルを採用してる。
その際、ユーザーからの新しい接続があった場合、MySQLはどのようにスレッドを作り、そのスレッドをどう動かしてるのか気になってしまった。
そこで、完全な知識ではない可能性があるものの、自分が調べた範囲での理解をこのページにまとめておくこととする。
接続とスレッド
クライアントから接続要求が来て、その要求処理を完了して接続終了するまでの間で起きる流れとスレッドの動きのお話。
キーワード(一緒に流れも簡単に想像できそう)
コネクション要求:
クライアントからの接続要求のこと。何も特別なものではなく、TCP/IPのコネクション要求を指す。
このコネクションはキューイングされて、以下のレシーバスレッドに随時処理される。
レシーバースレッド:
キューイングにあるコネクションを前から1つずつ処理し、そのコネクション用のユーザースレッド(OS依存)を作成、もしくは、スレッドキャッシュからスレッドを取り出して、後の処理をそのスレッドに任せる。
ちなみに、スレッドキャッシュにスレッドがない場合は、仕方ないのでスレッドを作成する。
スレッドキャッシュ:
決められた数の空スレッドを、接続要求に利用するスレッドに使い回すために保持するためのもの。
スレッド作成・破棄の処理時間を省くことで、少しでもレイテンシを上げようと努力してる。
ただ、最近のOSスレッド作成/破棄は割と低コストらしい。
thread_cache_sizeというパラメータで、スレッドキャッシュの大きさを設定可能。
ユーザースレッド:
クライアントからの要求処理をメインでお守りするスレッド。
最後にユーザーに「終わったよ」と返すのはこいつ。
基本的に、対応するTHD(後述)を確保&初期化し、認証を実施して、あとは要求クエリ内容を元に処理を進めていく。
MySQLスレッド界のエース。
THD:
クライアントからのコネクションの度に、新規生成されコネクションが閉じると同時に破棄される。
こいつは、そのコネクション固有の情報・データ(クエリの内容や結果も含む)を保持しておくための箱。
サイズは初期化時は〜10Kらしいが、それがクエリによっては増大するらしい。(ここの情報は曖昧onigiri.w2.icon)
「スレッドはSleepするんだ」という認識が大事
ユーザースレッドはまあOS依存なので、MySQLの複数スレッドの間でスイッチングが発生する。
簡単にだけ知識整理
スレッドやプロセスの状態は「実行可能」「実行中」「スリープ」「終了」などが存在。この4つだけまずは覚えておくといいかな。
複数スレッドが並行稼働する際、MySQLも例外ではなく、スライシングが発生しよる。
複数スレッドがCPUを交互に明け渡し合いながら、並行処理を実現してる。
MySQLにてCPUを明け渡す条件(これもOS知識の範囲ではある)
OSに決められた最大割り当て時間が来た時
スレッドにてストレージへのIO処理が発生した時(IO待ち)
スレッドにてロック待ちが発生した時
ここは後述するが、単純な話ではない....(スピンループっていう概念が入ってくる)
などなど
ユーザースレッドにて「ロック待ち」が起きた時の状況
調査に一番時間かかったとこ....onigiri.w2.icon
スレッドにてロック取得しようとした際、そのロックが別スレッドに取得されてたら...この時点からロック待ちが発生する。
ユーザースレッドは、すぐにCPUを他スレッドに明け渡してSleep状態に入るわけではない。
その前にスピンループていう処理を実施し、少しの間だけロックが解放されるのを待ってみる。 スピンループの回数には制限が決められており、パラメータから変更可能。
そして決められた回数分スピンループを実施したら、Sleep状態に入る。
その他Tips
MySQLは基本的に独自のスレッド実装を行うことはなく、OSのスレッド実装に依存してる。
スレッドキャッシュにフリーのスレッドが残ってないからと言って、新しい接続のスレッド生成が止まるわけではない。(ここ勘違いしやすい)
Q&A
q.icon
a.icon
参考